﻿using System.Collections.Concurrent;
using Basic.WxGatewayModular.Interface;
using Basic.WxGatewayModular.Model;
using Basic.WxRemoteModel.WxPlatform;
using Basic.WxRemoteModel.WxPlatform.Model;
using WeDonekRpc.Helper;
using WeDonekRpc.Helper.Lock;

namespace Basic.WxGatewayModular.Service
{
    internal class WxPlatformService : IWxPlatformService
    {
        private readonly ConcurrentDictionary<string, WxPlatform> _PlatformList = new ConcurrentDictionary<string, WxPlatform>();
        private readonly Timer _ClearTimer;

        public WxPlatformService ()
        {
            this._ClearTimer = new Timer(this._Clear, null, 60000, 60000);
        }

        private void _Clear (object? state)
        {
            if (this._PlatformList.IsEmpty)
            {
                return;
            }
            int now = HeartbeatTimeHelper.HeartbeatTime;
            string[] keys = this._PlatformList.Where(c => c.Value.OverTime <= now).Select(c => c.Key).ToArray();
            if (keys.Length > 0)
            {
                keys.ForEach(c =>
                {
                    _ = this._PlatformList.TryRemove(c, out _);
                });
            }
        }

        public WxPlatform Get (string appId)
        {
            if (!this._PlatformList.TryGetValue(appId, out WxPlatform platform))
            {
                using (DataSyncLock dataLock = SyncLockFactory.ApplyLock("Platform_" + appId))
                {
                    if (dataLock.GetLock())
                    {
                        WxPlatformDto dto = new GetWxPlatform
                        {
                            AppId = appId
                        }.Send();
                        platform = new WxPlatform(dto);
                        this._PlatformList.AddOrSet(appId, platform);
                        dataLock.Exit(platform);
                    }
                    else if (dataLock.Result != null)
                    {
                        return (WxPlatform)dataLock.Result;
                    }
                    else
                    {
                        throw new ErrorException("wx.platform.get.fail");
                    }
                }
            }
            return platform;
        }
        public string DecryptXml (string appId, string xml)
        {
            WxPlatform platform = this.Get(appId);
            return platform.Decrypt(xml);
        }
    }
}
